package com.sh.data.engine.domain.shims.sql.ddl;

import com.sh.data.engine.domain.base.model.enums.Database;
import com.sh.data.engine.domain.shims.sql.Context;
import com.sh.data.engine.domain.shims.sql.TerminalExpression;
import com.sh.data.engine.domain.shims.sql.ddl.CreateTableParam.FieldInfo;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author: mengzheng.mhc
 * @date: 2024/6/5 15:21
 */
public class DDL implements TerminalExpression {

    private final Context context;

    public DDL(Context context) {
        this.context = context;
    }

    public DDL(Context context, String sql) {
        this.context = context;
        this.context.append(sql);
    }

    public static DDL create(Context context, CreateTableParam param) {
        final DDL ddl = new DDL(context);
        DDLFactory.ddler(context.getDatabase()).create(context, param);
        return ddl;
    }

    public static DDL alterTableComment(
        Context context, String schema, String tableName, String comment) {
        final DDL ddl = new DDL(context);
        DDLFactory.ddler(context.getDatabase()).alterTableComment(context, schema, tableName, comment);
        return ddl;
    }

    public static DDL alterViewComment(
        Context context, String schema, String tableName, String comment) {
        final DDL ddl = new DDL(context);
        DDLFactory.ddler(context.getDatabase()).alterViewComment(context, schema, tableName, comment);
        return ddl;
    }

    public static DDL alterTableName(
        Context context, String schema, String tableName, String newTableName) {
        final DDL ddl = new DDL(context);
        DDLFactory.ddler(context.getDatabase())
            .alterTableName(context, schema, tableName, newTableName);
        return ddl;
    }

    public static DDL addTableField(
        Context context, String schema, String tableName, List<AddTableFieldParam> paramList) {
        final DDL ddl = new DDL(context);
        DDLFactory.ddler(context.getDatabase()).addTableField(context, schema, tableName, paramList);
        return ddl;
    }

    public static DDL editTableField(
        Context context, String schema, String tableName, List<EditTableFieldParam> paramList) {
        final DDL ddl = new DDL(context);
        DDLFactory.ddler(context.getDatabase()).editTableField(context, schema, tableName, paramList);
        return ddl;
    }

    public static DDL deleteTableField(
        Context context, String schema, String tableName, List<String> fieldList) {
        final DDL ddl = new DDL(context);
        DDLFactory.ddler(context.getDatabase()).deleteTableField(context, schema, tableName, fieldList);
        return ddl;
    }

    public static DDL dropTable(Context context, String schema, String tableName) {
        final DDL ddl = new DDL(context);
        DDLFactory.ddler(context.getDatabase()).dropTable(context, schema, tableName);
        return ddl;
    }

    public static DDL getTableField(Context context, String schema, String tableName) {
        final DDL ddl = new DDL(context);
        DDLFactory.ddler(context.getDatabase()).getTableField(context, schema, tableName);
        return ddl;
    }

    public static DDL replaceTableFields(
        Context context, String schema, String tableName, List<AddTableFieldParam> fieldLists) {
        final DDL ddl = new DDL(context);
        DDLFactory.ddler(context.getDatabase())
            .replaceTableFields(context, schema, tableName, fieldLists);
        return ddl;
    }

    @Override
    public String toString() {
        return context.toString();
    }

    @Override
    public void execute() throws SQLException {
        context.execute();
    }
}

interface DDLer {

    /**
     * 创建表
     *
     * @param context
     * @param param
     * @return
     */
    Context create(Context context, CreateTableParam param);

    /**
     * 修改表名
     *
     * @param context
     * @param schema
     * @param tableName
     * @param newTableName
     * @return
     */
    default Context alterTableName(
        Context context, String schema, String tableName, String newTableName) {
        if (StringUtils.isBlank(newTableName)) {
            return context;
        }

        if (StringUtils.equals(tableName, newTableName)) {
            return context;
        }

        tableName = normalizedTableName(context.getEscape(), schema, tableName);
        // pg 语法报错, ALTER TABLE "hufu"."origin_table_name" RENAME TO "hufu"."new_test_table_name";
        // newTableName = normalizedTableName(context.getEscape(), schema, newTableName);

        context
            .appendWithSeparator("ALTER TABLE")
            .appendWithSeparator(tableName)
            .appendWithSeparator("RENAME TO")
            .appendWithSeparator(newTableName);

        return context;
    }

    /**
     * 修改表注释
     *
     * @param context
     * @param schema
     * @param tableName
     * @param comment
     * @return
     */
    Context alterTableComment(Context context, String schema, String tableName, String comment);

    /**
     * 修改视图注释
     *
     * @param context
     * @param schema
     * @param tableName
     * @param comment
     * @return
     */
    Context alterViewComment(Context context, String schema, String tableName, String comment);

    /**
     * 修改表属性，针对hive
     *
     * @param context
     * @param schema
     * @param tableName
     * @param tblProperties
     * @return
     */
    default Context alterTableProp(
        Context context, String schema, String tableName, Map<String, String> tblProperties) {
        throw new UnsupportedOperationException("暂不支持的操作");
    }

    /**
     * 添加表字段
     *
     * @param context
     * @param schema
     * @param tableName
     * @param paramList
     * @return
     */
    Context addTableField(
        Context context, String schema, String tableName, List<AddTableFieldParam> paramList);

    /**
     * 编辑表字段，包括编辑字段名、字段类型、字段注释
     *
     * @param context
     * @param schema
     * @param tableName
     * @param paramList
     * @return
     */
    Context editTableField(
        Context context, String schema, String tableName, List<EditTableFieldParam> paramList);

    /**
     * 删除表字段
     *
     * @param context
     * @param schema
     * @param tableName
     * @param fieldList
     * @return
     */
    Context deleteTableField(
        Context context, String schema, String tableName, List<String> fieldList);

    /**
     * 删除表
     *
     * @param context
     * @param schema
     * @param tableName
     * @return
     */
    default Context dropTable(Context context, String schema, String tableName) {
        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        context.appendWithSeparator("DROP TABLE").appendWithSeparator(tableName);

        return context;
    }

    /**
     * 标准化表名，若无schema，则表名用escape包裹；若有schema，则表名和schema组在一起使用
     *
     * @param escape
     * @param schema
     * @param tableName
     * @return
     */
    default String normalizedTableName(String escape, String schema, String tableName) {
        StringBuilder tableNameBuilder = new StringBuilder();
        if (StringUtils.isBlank(schema)) {
            tableNameBuilder.append(escape).append(tableName).append(escape);
        } else {
            tableNameBuilder
                .append(escape)
                .append(schema)
                .append(escape)
                .append(Context.CONNECTOR)
                .append(escape)
                .append(tableName)
                .append(escape);
        }

        return tableNameBuilder.toString();
    }

    Context getTableField(Context context, String schema, String tableName);

    default Context replaceTableFields(
        Context context, String schema, String tableName, List<AddTableFieldParam> fieldLists) {
        throw new UnsupportedOperationException("hive support");
    }
}

class HiveDDLer implements DDLer {

    private static Pattern PATTERN =
        Pattern.compile("(VARCHAR|CHAR|DECIMAL)\\((\\d+)\\)", Pattern.CASE_INSENSITIVE);

    @Override
    public Context create(Context context, CreateTableParam param) {
        context.appendWithSeparator("CREATE");
        if (param.isExternal()) {
            context.appendWithSeparator("EXTERNAL");
        }
        context.appendWithSeparator("TABLE IF NOT EXISTS");

        context.append(
            normalizedTableName(context.getEscape(), param.getSchema(), param.getTableName()));

        context.appendWithSeparator("(");

        List<FieldInfo> fieldInfoList = param.getFieldInfoList();
        for (int i = 0; i < fieldInfoList.size(); i++) {
            context
                .appendWithEscape(fieldInfoList.get(i).getFieldName())
                .appendWithSeparator("")
                .appendWithSeparator(fieldInfoList.get(i).getFieldType())
                .appendWithSeparator("COMMENT")
                .append("'")
                .append(
                    StringUtils.isBlank(fieldInfoList.get(i).getComment())
                        ? " "
                        : fieldInfoList.get(i).getComment())
                .append("'");
            if (i < fieldInfoList.size() - 1) {
                context.append(",").append("\n");
            } else {
                context.append(")").append("\n");
            }
        }

        context
            .appendWithSeparator("COMMENT")
            .append("'")
            .append(param.getTableComment() == null ? " " : param.getTableComment())
            .append("'\n");

        if (CollectionUtils.isNotEmpty(param.getPartitionFieldList())) {
            context.append("PARTITIONED BY (");

            List<FieldInfo> partitionFieldList = param.getPartitionFieldList();
            for (int i = 0; i < partitionFieldList.size(); i++) {
                FieldInfo fieldInfo = partitionFieldList.get(i);
                context
                    .appendWithEscape(fieldInfo.getFieldName())
                    .appendWithSeparator("")
                    .appendWithSeparator(fieldInfo.getFieldType())
                    .appendWithSeparator("COMMENT")
                    .append("'")
                    .append(StringUtils.isBlank(fieldInfo.getComment()) ? " " : fieldInfo.getComment())
                    .append("'");
                if (i < partitionFieldList.size() - 1) {
                    context.append(",").append("\n");
                } else {
                    context.append(")").append("\n");
                }
            }
        }

        if (StringUtils.isNotBlank(param.getStoreType())) {
            context.append("STORED AS ").append(param.getStoreType()).append("\n");
        }

        if (null != param.getTblProperties()) {
            context.appendWithSeparator("TBLPROPERTIES (");
            param
                .getTblProperties()
                .forEach(
                    (k, v) -> {
                        context.append("'").append(k).append("' = '").append(v).append("'").append(",");
                    });
            context.deleteCharAt(context.getCurrentSql().length() - 1);
            context.append(")");
        }

        return context;
    }

    @Override
    public Context alterTableComment(
        Context context, String schema, String tableName, String comment) {
        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        context
            .appendWithSeparator("ALTER TABLE")
            .appendWithSeparator(tableName)
            .append(" SET TBLPROPERTIES('comment' = '")
            .append(comment)
            .append("')");

        return context;
    }

    @Override
    public Context alterViewComment(
        Context context, String schema, String tableName, String comment) {
        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        context
            .appendWithSeparator("ALTER VIEW")
            .appendWithSeparator(tableName)
            .append(" SET TBLPROPERTIES('comment' = '")
            .append(comment)
            .append("')");

        return context;
    }


    @Override
    public Context alterTableProp(
        Context context, String schema, String tableName, Map<String, String> tblProperties) {
        if (null == tblProperties || tblProperties.isEmpty()) {
            return context;
        }

        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        context
            .appendWithSeparator("ALTER TABLE")
            .appendWithSeparator(tableName)
            .appendWithSeparator("SET TBLPROPERTIES (");

        tblProperties.forEach(
            (k, v) -> {
                context.append("'").append(k).append("' = '").append(v).append("'").append(",");
            });
        context.deleteCharAt(context.getCurrentSql().length() - 1);
        context.append(")");

        return context;
    }

    @Override
    public Context addTableField(
        Context context, String schema, String tableName, List<AddTableFieldParam> paramList) {
        if (CollectionUtils.isEmpty(paramList)) {
            return context;
        }

        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        context
            .appendWithSeparator("ALTER TABLE")
            .appendWithSeparator(tableName)
            .appendWithSeparator("ADD COLUMNS (");

        for (AddTableFieldParam addTableFieldParam : paramList) {
            context
                .appendWithEscape(addTableFieldParam.getFieldName())
                .appendWithSeparator(normalizedSpecialType(addTableFieldParam.getFieldType()))
                .appendWithSeparator("COMMENT")
                .append("'")
                .append(StringUtils.defaultString(addTableFieldParam.getComment()))
                .append("'")
                .append(",");
        }
        context.deleteCharAt(context.toString().length() - 1);
        context.append(")");

        return context;
    }

    @Override
    public Context editTableField(
        Context context, String schema, String tableName, List<EditTableFieldParam> paramList) {
        if (CollectionUtils.isEmpty(paramList)) {
            return context;
        }

        tableName = normalizedTableName(context.getEscape(), schema, tableName);
        paramList.forEach(
            p -> {
                if (StringUtils.isBlank(p.getNewFieldName())) {
                    p.setNewFieldName(p.getFieldName());
                }
            });

        for (EditTableFieldParam editTableFieldParam : paramList) {
            context
                .appendWithSeparator("ALTER TABLE")
                .appendWithSeparator(tableName)
                .appendWithSeparator("CHANGE")
                .appendWithEscape(editTableFieldParam.getFieldName())
                .append(" ")
                .appendWithEscape(editTableFieldParam.getNewFieldName())
                .appendWithSeparator(normalizedSpecialType(editTableFieldParam.getFieldType()))
                .appendWithSeparator("COMMENT")
                .append("'")
                .append(StringUtils.defaultString(editTableFieldParam.getComment()))
                .append("'")
                .appendNewSql();
        }

        return context;
    }

    @Override
    public Context deleteTableField(
        Context context, String schema, String tableName, List<String> fieldList) {
        throw new UnsupportedOperationException("hive doesn't support delete field");
    }

    /**
     * hive通过 describe 语句获取字段信息时会把分区信息也带出来
     *
     * @param context
     * @param schema
     * @param tableName
     * @return
     */
    @Override
    public Context getTableField(Context context, String schema, String tableName) {
        tableName = normalizedTableName(context.getEscape(), schema, tableName);
        return context.appendWithSeparator("DESCRIBE " + tableName);
    }

    public static String normalizedSpecialType(String fieldType) {
        fieldType = StringUtils.upperCase(StringUtils.trim(fieldType));
        if (StringUtils.startsWith(fieldType, "VARCHAR")) {
            // max length 65355
            Matcher m = PATTERN.matcher(fieldType);
            if (!m.find() || Integer.parseInt(m.group(2)) > 65355) {
                fieldType = "VARCHAR(400)";
            }
        } else if (StringUtils.startsWith(fieldType, "CHAR")) {
            // max length 255
            Matcher m = PATTERN.matcher(fieldType);
            if (!m.find() || Integer.parseInt(m.group(2)) > 255) {
                fieldType = "CHAR(255)";
            }
        } else if (StringUtils.startsWith(fieldType, "DECIMAL")) {
            fieldType = "DECIMAL(20,10)";
        }
        return fieldType;
    }

    @Override
    public Context replaceTableFields(
        Context context, String schema, String tableName, List<AddTableFieldParam> fieldLists) {
        if (CollectionUtils.isEmpty(fieldLists)) {
            return context;
        }

        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        context.appendWithSeparator("ALTER TABLE").appendWithSeparator(tableName);

        context.appendWithSeparator("REPLACE COLUMNS (");
        for (int i = 0; i < fieldLists.size(); i++) {
            AddTableFieldParam addTableFieldParam = fieldLists.get(i);
            context
                .appendWithEscape(addTableFieldParam.getFieldName())
                .append(" ")
                .appendWithSeparator(normalizedSpecialType(addTableFieldParam.getFieldType()))
                .appendWithSeparator("COMMENT")
                .append("'")
                .append(StringUtils.defaultString(addTableFieldParam.getComment()))
                .append("'");
            if (i != fieldLists.size() - 1) {
                context.append(",");
            }
        }
        context.appendWithSeparator(")");
        return context;
    }
}

class PostgresSqlDDLer implements DDLer {

    @Override
    public Context create(Context context, CreateTableParam param) {

        String tableName =
            normalizedTableName(context.getEscape(), param.getSchema(), param.getTableName());

        context.appendWithSeparator("CREATE TABLE IF NOT EXISTS");

        context.appendWithSeparator(tableName);

        context.appendWithSeparator("(");

        for (CreateTableParam.FieldInfo fieldInfo : param.getFieldInfoList()) {
            context.appendWithEscape(fieldInfo.getFieldName()).append(" ");

            if (fieldInfo.isAutoIncrement()) {
                context.appendWithSeparator("serial");
            } else {
                context.appendWithSeparator(fieldInfo.getFieldType());
            }

            if (!fieldInfo.isNullable()) {
                context.appendWithSeparator("NOT NULL");
            }

            if (StringUtils.isNotBlank(fieldInfo.getDefaultVal())) {
                context.appendWithSeparator("DEFAULT").appendWithSeparator(fieldInfo.getDefaultVal());
            }
            context.append(",");
        }

        final List<FieldInfo> primaryFields =
            param.getFieldInfoList().stream()
                .filter(FieldInfo::isPrimaryKey)
                .collect(Collectors.toList());

        if (CollectionUtils.isNotEmpty(primaryFields)) {
            context.appendWithSeparator("PRIMARY KEY (");
            primaryFields.forEach(f -> context.appendWithEscape(f.getFieldName()).append(","));
            context.deleteCharAt(context.getCurrentSql().length() - 1);
            context.append(")");
        } else {
            context.deleteCharAt(context.getCurrentSql().length() - 1);
        }

        context.appendWithSeparator(")").appendNewSql();

        if (StringUtils.isNotBlank(param.getTableComment())) {
            context.appendWithSeparator("COMMENT ON TABLE");
            context.appendWithSeparator(tableName);
            context.append("is '").append(param.getTableComment()).append("'").appendNewSql();
        }

        final List<CreateTableParam.FieldInfo> hasCommentFields =
            param.getFieldInfoList().stream()
                .filter(f -> StringUtils.isNotBlank(f.getComment()))
                .collect(Collectors.toList());
        hasCommentFields.forEach(
            f -> {
                context.appendWithSeparator("COMMENT ON COLUMN");
                context.append(tableName).append(Context.CONNECTOR).appendWithEscape(f.getFieldName());
                context.append(" is '").append(f.getComment()).append("'").appendNewSql();
            });

        return context;
    }

    @Override
    public Context alterTableComment(
        Context context, String schema, String tableName, String comment) {
        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        context
            .appendWithSeparator("comment on table")
            .appendWithSeparator(tableName)
            .appendWithSeparator("is")
            .append("'")
            .append(comment)
            .append("'");

        return context;
    }

    @Override
    public Context alterViewComment(
        Context context, String schema, String tableName, String comment) {
        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        context
            .appendWithSeparator("comment on view")
            .appendWithSeparator(tableName)
            .appendWithSeparator("is")
            .append("'")
            .append(comment)
            .append("'");

        return context;
    }

    @Override
    public Context addTableField(
        Context context, String schema, String tableName, List<AddTableFieldParam> paramList) {
        if (CollectionUtils.isEmpty(paramList)) {
            return context;
        }

        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        for (AddTableFieldParam addTableFieldParam : paramList) {
            context
                .appendWithSeparator("ALTER table")
                .appendWithSeparator(tableName)
                .appendWithSeparator("ADD COLUMN")
                .appendWithEscape(addTableFieldParam.getFieldName())
                .appendWithSeparator(addTableFieldParam.getFieldType())
                .appendWithSeparator(addTableFieldParam.isNullable() ? "DEFAULT null" : "not null")
                .append(";\n");
            if (StringUtils.isNotBlank(addTableFieldParam.getComment())) {
                context
                    .appendWithSeparator("COMMENT ON COLUMN")
                    .append(tableName)
                    .append(".")
                    .appendWithEscape(addTableFieldParam.getFieldName())
                    .appendWithSeparator("")
                    .appendWithSeparator("is")
                    .append("'")
                    .append(addTableFieldParam.getComment())
                    .append("'")
                    .appendNewSql();
            }
        }

        return context;
    }

    /**
     * alter column type时候添加 using "expression" 强制转换
     *
     * @param context
     * @param schema
     * @param tableName
     * @param paramList
     * @return
     */
    @Override
    public Context editTableField(
        Context context, String schema, String tableName, List<EditTableFieldParam> paramList) {
        if (CollectionUtils.isEmpty(paramList)) {
            return context;
        }

        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        for (EditTableFieldParam editTableFieldParam : paramList) {
            if (!StringUtils.equals(
                editTableFieldParam.getFieldName(), editTableFieldParam.getNewFieldName())
                && StringUtils.isNoneBlank(editTableFieldParam.getNewFieldName())) {
                context
                    .appendWithSeparator("ALTER TABLE ")
                    .appendWithSeparator(tableName)
                    .appendWithSeparator(" RENAME ")
                    .appendWithEscape(editTableFieldParam.getFieldName())
                    .appendWithSeparator(" to ")
                    .appendWithEscape(editTableFieldParam.getNewFieldName())
                    .appendNewSql();
            }
            String fieldName = Objects.requireNonNullElse(
                editTableFieldParam.getNewFieldName(), editTableFieldParam.getFieldName());
            // 修改类型 和 是否可空
            context
                .appendWithSeparator("alter table")
                .appendWithSeparator(tableName)
                .appendWithSeparator("alter COLUMN")
                .appendWithEscape(fieldName)
                .appendWithSeparator(" type")
                .appendWithSeparator(editTableFieldParam.getFieldType())
                .appendWithSeparator("USING")
                .appendWithEscape(fieldName)
                .append("::" + editTableFieldParam.getFieldType())
                .append(",")
                .appendWithSeparator("alter COLUMN")
                .appendWithEscape(fieldName)
                .appendWithSeparator(
                    editTableFieldParam.getNullable() != null && editTableFieldParam.getNullable()
                        ? "DROP NOT NULL" : " SET NOT NULL")
                .appendNewSql();
            context
                .appendWithSeparator("COMMENT ON COLUMN")
                .append(tableName)
                .append(".")
                .appendWithEscape(fieldName)
                .appendWithSeparator("")
                .appendWithSeparator("is")
                .append("'")
                .append(StringUtils.defaultString(editTableFieldParam.getComment()))
                .append("'")
                .appendNewSql();
        }
        return context;
    }

    @Override
    public Context deleteTableField(
        Context context, String schema, String tableName, List<String> fieldList) {
        if (CollectionUtils.isEmpty(fieldList)) {
            return context;
        }
        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        for (String field : fieldList) {
            context
                .appendWithSeparator("alter table")
                .appendWithSeparator(tableName)
                .appendWithSeparator("drop column if exists")
                .appendWithEscape(field)
                .appendNewSql();
        }
        return context;
    }

    /**
     * pgsql可以在命令行通过" \d {tablename}"的方式查看, jdbc不支持"\d"这种语法, 通过pg_catalog, information_schema等元信息来查
     *
     * @param context
     * @param schema
     * @param tableName
     * @return
     */
    @Override
    public Context getTableField(Context context, String schema, String tableName) {
        context
            .append(
                "SELECT cols.column_name, cols.data_type, cols.is_nullable , pg_catalog.col_description(c.oid, cols.ordinal_position::int) as comment "
                    + "FROM pg_catalog.pg_class c, information_schema.columns cols WHERE ")
            .append("cols.table_schema=")
            .append("'")
            .append(schema)
            .append("' AND ")
            .append("cols.table_name =")
            .append("'")
            .append(tableName)
            .append("' AND ")
            .append("cols.table_name = c.relname");
        return context;
    }
}

/**
 * tidb sql
 */
class TidbSqlDDLer implements DDLer {

    @Override
    public Context create(Context context, CreateTableParam param) {

        String tableName =
            normalizedTableName(context.getEscape(), param.getSchema(), param.getTableName());

        context.appendWithSeparator("CREATE TABLE IF NOT EXISTS");

        context.appendWithSeparator(tableName);

        context.appendWithSeparator("(");

        int i = 0;
        for (CreateTableParam.FieldInfo fieldInfo : param.getFieldInfoList()) {
            i++;
            context.appendWithEscape(fieldInfo.getFieldName()).append(" ");

            context.appendWithSeparator(fieldInfo.getFieldType());

            if (fieldInfo.isAutoIncrement()) {
                context.appendWithSeparator("AUTO_INCREMENT");
            }

            if (!fieldInfo.isNullable()) {
                context.appendWithSeparator("NOT NULL");
            }

            if (StringUtils.isNotBlank(fieldInfo.getDefaultVal())) {
                context.appendWithSeparator("DEFAULT").appendWithSeparator(fieldInfo.getDefaultVal());
            }

            if (StringUtils.isNotBlank(fieldInfo.getComment())) {
                context
                    .appendWithSeparator("COMMENT")
                    .append("'")
                    .append(fieldInfo.getComment())
                    .append("'");
            }
            context.append(",");
            if (param.getFieldInfoList().size() != i) {
                context.append(" \n");
            }
        }

        final List<FieldInfo> primaryFields =
            param.getFieldInfoList().stream()
                .filter(FieldInfo::isPrimaryKey)
                .collect(Collectors.toList());

        if (CollectionUtils.isNotEmpty(primaryFields)) {
            context.appendWithSeparator("PRIMARY KEY (");
            primaryFields.forEach(f -> context.appendWithEscape(f.getFieldName()).append(","));
            context.deleteCharAt(context.getCurrentSql().length() - 1);
            context.append(")");
        } else {
            context.deleteCharAt(context.getCurrentSql().length() - 1);
        }

        context.appendWithSeparator(")");

        if (StringUtils.isNotBlank(param.getTableComment())) {
            context.appendWithSeparator("COMMENT = ");
            context.append("'").append(param.getTableComment()).append("'").appendNewSql();
        }

        return context;
    }

    @Override
    public Context alterTableComment(
        Context context, String schema, String tableName, String comment) {
        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        context
            .appendWithSeparator("ALTER TABLE")
            .appendWithSeparator(tableName)
            .appendWithSeparator("COMMENT")
            .append("'")
            .append(comment)
            .append("'");

        return context;
    }

    @Override
    public Context alterViewComment(
        Context context, String schema, String tableName, String comment) {
        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        context
            .appendWithSeparator("ALTER VIEW")
            .appendWithSeparator(tableName)
            .appendWithSeparator("COMMENT")
            .append("'")
            .append(comment)
            .append("'");

        return context;
    }

    /**
     * tidb: 不支持在一条语句中同时添加多列! 不支持将新添加的列设为 PRIMARY KEY! 不支持将新添加的列设为 AUTO_INCREMENT!
     *
     * @param context
     * @param schema
     * @param tableName
     * @param paramList
     * @return
     */
    @Override
    public Context addTableField(
        Context context, String schema, String tableName, List<AddTableFieldParam> paramList) {
        if (CollectionUtils.isEmpty(paramList)) {
            return context;
        }

        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        for (AddTableFieldParam addTableFieldParam : paramList) {
            Context baseContext =
                context
                    .appendWithSeparator("ALTER table")
                    .appendWithSeparator(tableName)
                    .appendWithSeparator("ADD COLUMN")
                    .appendWithEscape(addTableFieldParam.getFieldName())
                    .appendWithSeparator("")
                    .appendWithSeparator(addTableFieldParam.getFieldType())
                    .appendWithSeparator(addTableFieldParam.isNullable() ? "null" : "not null")
                    .appendWithSeparator("COMMENT")
                    .append("'")
                    .append(addTableFieldParam.getComment())
                    .append("'")
                    .append(";\n")
                    .appendNewSql();
        }

        return context;
    }

    /**
     * use CHANGE update column name and type
     *
     * @param context
     * @param schema
     * @param tableName
     * @param paramList
     * @return
     */
    @Override
    public Context editTableField(
        Context context, String schema, String tableName, List<EditTableFieldParam> paramList) {
        if (CollectionUtils.isEmpty(paramList)) {
            return context;
        }

        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        for (EditTableFieldParam editTableFieldParam : paramList) {
            context
                .appendWithSeparator("ALTER TABLE ")
                .appendWithSeparator(tableName)
                .appendWithSeparator("CHANGE")
                .appendWithEscape(editTableFieldParam.getFieldName())
                .appendWithSeparator("")
                .appendWithEscape(editTableFieldParam.getNewFieldName())
                .appendWithSeparator("")
                .appendWithSeparator(editTableFieldParam.getFieldType())
                .appendWithSeparator(
                    editTableFieldParam.getNullable() != null && editTableFieldParam.getNullable()
                        ? "NULL" : "NOT NULL")
                .appendWithSeparator("COMMENT ")
                .append("'")
                .append(editTableFieldParam.getComment())
                .append("'")
                .appendNewSql();
        }
        return context;
    }

    @Override
    public Context deleteTableField(
        Context context, String schema, String tableName, List<String> fieldList) {
        if (CollectionUtils.isEmpty(fieldList)) {
            return context;
        }
        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        for (String field : fieldList) {
            context
                .appendWithSeparator("alter table")
                .appendWithSeparator(tableName)
                .appendWithSeparator("drop column if exists")
                .appendWithEscape(field)
                .appendNewSql();
        }
        return context;
    }

    /**
     * @param context
     * @param schema
     * @param tableName
     * @return
     */
    @Override
    public Context getTableField(Context context, String schema, String tableName) {
        context
            .append("SELECT * FROM information_schema.columns WHERE table_schema=")
            .append("'")
            .append(schema)
            .append("' AND ")
            .append("TABLE_NAME=")
            .append("'")
            .append(tableName)
            .append("'");
        return context;
    }
}

class SAPSqlDDLer implements DDLer {

    @Override
    public Context create(Context context, CreateTableParam param) {

        String tableName =
            normalizedTableName(context.getEscape(), param.getSchema(), param.getTableName());

        context.appendWithSeparator("CREATE TABLE");

        context.appendWithSeparator(tableName);

        context.appendWithSeparator("(");

        for (CreateTableParam.FieldInfo fieldInfo : param.getFieldInfoList()) {
            context
                .appendWithEscape(fieldInfo.getFieldName())
                .append(" ")
                .appendWithSeparator(fieldInfo.getFieldType());

            if (fieldInfo.isAutoIncrement()) {
                context.appendWithSeparator("GENERATED ALWAYS AS IDENTITY");
            }

            if (!fieldInfo.isNullable()) {
                context.appendWithSeparator("NOT NULL");
            }

            if (StringUtils.isNotBlank(fieldInfo.getDefaultVal())) {
                context.appendWithSeparator("DEFAULT").appendWithSeparator(fieldInfo.getDefaultVal());
            }

            if (StringUtils.isNotBlank(fieldInfo.getComment())) {
                context
                    .appendWithSeparator("COMMENT")
                    .append("'")
                    .append(fieldInfo.getComment())
                    .appendWithSeparator("'");
            }

            context.append(",");
        }

        final List<FieldInfo> primaryFields =
            param.getFieldInfoList().stream()
                .filter(f -> f.isPrimaryKey())
                .collect(Collectors.toList());

        if (CollectionUtils.isNotEmpty(primaryFields)) {
            context.appendWithSeparator("PRIMARY KEY INVERTED VALUE (");
            primaryFields.forEach(
                f -> {
                    context.appendWithEscape(f.getFieldName()).append(",");
                });
            context.deleteCharAt(context.getCurrentSql().length() - 1);
            context.append("),");
        }

        context.deleteCharAt(context.getCurrentSql().length() - 1);

        context.appendWithSeparator(") UNLOAD PRIORITY 5 AUTO MERGE").appendNewSql();

        if (StringUtils.isNotBlank(param.getTableComment())) {
            context.appendWithSeparator("COMMENT ON TABLE");
            context.appendWithSeparator(tableName);
            context.append("is '").append(param.getTableComment()).append("'").appendNewSql();
        }

        return context;
    }

    @Override
    public Context alterTableComment(
        Context context, String schema, String tableName, String comment) {
        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        context
            .appendWithSeparator("comment on table")
            .appendWithSeparator(tableName)
            .appendWithSeparator("is")
            .append("'")
            .append(comment)
            .append("'");

        return context;
    }

    @Override
    public Context alterViewComment(
        Context context, String schema, String tableName, String comment) {
        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        context
            .appendWithSeparator("comment on view")
            .appendWithSeparator(tableName)
            .appendWithSeparator("is")
            .append("'")
            .append(comment)
            .append("'");

        return context;
    }

    /**
     * sap support add multi columns in single sql
     *
     * @param context
     * @param schema
     * @param tableName
     * @param paramList
     * @return
     */
    @Override
    public Context addTableField(
        Context context, String schema, String tableName, List<AddTableFieldParam> paramList) {
        if (CollectionUtils.isEmpty(paramList)) {
            return context;
        }

        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        context
            .appendWithSeparator("ALTER table")
            .appendWithSeparator(tableName)
            .appendWithSeparator("ADD (");
        for (int i = 0; i < paramList.size(); i++) {
            AddTableFieldParam addTableFieldParam = paramList.get(i);
            context
                .appendWithEscape(addTableFieldParam.getFieldName())
                .appendWithSeparator("")
                .appendWithSeparator(addTableFieldParam.getFieldType())
                .appendWithSeparator(addTableFieldParam.isNullable() ? "null" : "not null");
            if (StringUtils.isNotBlank(addTableFieldParam.getComment())) {
                context
                    .appendWithSeparator(" COMMENT ")
                    .append("'" + addTableFieldParam.getComment() + "'");
            }
            if (i != paramList.size() - 1) {
                context.appendWithSeparator(",");
            }
        }
        context.append(");\n");

        return context;
    }

    /**
     * alter column type时候添加 using "expression" 强制转换
     *
     * @param context
     * @param schema
     * @param tableName
     * @param paramList
     * @return
     */
    @Override
    public Context editTableField(
        Context context, String schema, String tableName, List<EditTableFieldParam> paramList) {
        if (CollectionUtils.isEmpty(paramList)) {
            return context;
        }

        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        for (EditTableFieldParam editTableFieldParam : paramList) {
            if (!StringUtils.equals(
                editTableFieldParam.getFieldName(), editTableFieldParam.getNewFieldName())
                && StringUtils.isNoneBlank(editTableFieldParam.getNewFieldName())) {
                context
                    .appendWithSeparator("RENAME COLUMN ")
                    .append(tableName)
                    .append(".")
                    .appendWithEscape(editTableFieldParam.getFieldName())
                    .appendWithSeparator(" to ")
                    .appendWithEscape(editTableFieldParam.getNewFieldName())
                    .appendNewSql();
            }
            String fieldName = Objects.requireNonNullElse(editTableFieldParam.getNewFieldName(), editTableFieldParam.getFieldName());
            // 修改类型 和 是否可空
            context
                .appendWithSeparator("alter table")
                .appendWithSeparator(tableName)
                .appendWithSeparator("alter (")
                .appendWithEscape(fieldName)
                .appendWithSeparator("")
                .appendWithSeparator(editTableFieldParam.getFieldType())
                // .appendWithSeparator(editTableFieldParam.isNullable() ? "DEFAULT NULL" : " NOT NULL")
                // //sap text类型不能default null
                .append(")")
                .appendNewSql();
            context
                .appendWithSeparator("COMMENT ON COLUMN")
                .append(tableName)
                .append(".")
                .appendWithEscape(fieldName)
                .appendWithSeparator("")
                .appendWithSeparator("is")
                .append("'")
                .append(StringUtils.defaultString(editTableFieldParam.getComment()))
                .append("'")
                .appendNewSql();
        }
        return context;
    }

    @Override
    public Context deleteTableField(
        Context context, String schema, String tableName, List<String> fieldList) {
        if (CollectionUtils.isEmpty(fieldList)) {
            return context;
        }
        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        for (String field : fieldList) {
            context
                .appendWithSeparator("alter table")
                .appendWithSeparator(tableName)
                .appendWithSeparator("drop (")
                .appendWithEscape(field)
                .append(")")
                .appendNewSql();
        }
        return context;
    }

    /**
     * @param context
     * @param schema
     * @param tableName
     * @return
     */
    @Override
    public Context getTableField(Context context, String schema, String tableName) {
        context
            .append(
                "SELECT c.column_name,c.data_type_name,c.is_nullable,c.comments FROM table_columns c LEFT JOIN tables t "
                    + "ON c.table_oid = t.table_oid WHERE t.TABLE_NAME = '")
            .append(tableName)
            .append("' AND t.schema_name = '")
            .append(schema)
            .append("'");
        return context;
    }

    /**
     * sap rename table
     *
     * @param context
     * @param schema
     * @param tableName
     * @param newTableName
     * @return
     */
    @Override
    public Context alterTableName(
        Context context, String schema, String tableName, String newTableName) {
        //  RENAME TABLE <current_table_name> TO <new_table_name>
        if (StringUtils.isBlank(newTableName)) {
            return context;
        }

        if (StringUtils.equals(tableName, newTableName)) {
            return context;
        }

        tableName = normalizedTableName(context.getEscape(), schema, tableName);
        // pg 语法报错, ALTER TABLE "hufu"."origin_table_name" RENAME TO "hufu"."new_test_table_name";
        // newTableName = normalizedTableName(context.getEscape(), schema, newTableName);

        context
            .appendWithSeparator("RENAME TABLE")
            .appendWithSeparator(tableName)
            .appendWithSeparator("TO")
            .appendWithEscape(newTableName);

        return context;
    }

}

class Kingbase8DDLer implements DDLer {

    @Override
    public Context create(Context context, CreateTableParam param) {
        String tableName =
            normalizedTableName(context.getEscape(), param.getSchema(), param.getTableName());

        context.appendWithSeparator("CREATE TABLE IF NOT EXISTS");

        context.appendWithSeparator(tableName);

        context.appendWithSeparator("(");

        for (CreateTableParam.FieldInfo fieldInfo : param.getFieldInfoList()) {
            context.appendWithEscape(fieldInfo.getFieldName()).append(" ");

            if (fieldInfo.isAutoIncrement()) {
                context.appendWithSeparator("serial");
            } else {
                context.appendWithSeparator(fieldInfo.getFieldType());
            }

            if (!fieldInfo.isNullable()) {
                context.appendWithSeparator("NOT NULL");
            }

            if (StringUtils.isNotBlank(fieldInfo.getDefaultVal())) {
                context.appendWithSeparator("DEFAULT").appendWithSeparator(fieldInfo.getDefaultVal());
            }
            context.append(",");
        }

        final List<FieldInfo> primaryFields =
            param.getFieldInfoList().stream()
                .filter(FieldInfo::isPrimaryKey)
                .collect(Collectors.toList());

        if (CollectionUtils.isNotEmpty(primaryFields)) {
            context.appendWithSeparator("PRIMARY KEY (");
            primaryFields.forEach(f -> context.appendWithEscape(f.getFieldName()).append(","));
            context.deleteCharAt(context.getCurrentSql().length() - 1);
            context.append(")");
        } else {
            context.deleteCharAt(context.getCurrentSql().length() - 1);
        }

        context.appendWithSeparator(")").appendNewSql();

        if (StringUtils.isNotBlank(param.getTableComment())) {
            context.appendWithSeparator("COMMENT ON TABLE");
            context.appendWithSeparator(tableName);
            context.append("is '").append(param.getTableComment()).append("'").appendNewSql();
        }

        final List<CreateTableParam.FieldInfo> hasCommentFields =
            param.getFieldInfoList().stream()
                .filter(f -> StringUtils.isNotBlank(f.getComment()))
                .collect(Collectors.toList());
        hasCommentFields.forEach(
            f -> {
                context.appendWithSeparator("COMMENT ON COLUMN");
                context.append(tableName).append(Context.CONNECTOR).appendWithEscape(f.getFieldName());
                context.append(" is '").append(f.getComment()).append("'").appendNewSql();
            });

        return context;
    }

    @Override
    public Context alterTableComment(Context context, String schema, String tableName,
                                     String comment) {
        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        context
            .appendWithSeparator("comment on table")
            .appendWithSeparator(tableName)
            .appendWithSeparator("is")
            .append("'")
            .append(comment)
            .append("'");

        return context;
    }

    @Override
    public Context alterViewComment(Context context, String schema, String tableName,
                                    String comment) {
        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        context
            .appendWithSeparator("comment on view")
            .appendWithSeparator(tableName)
            .appendWithSeparator("is")
            .append("'")
            .append(comment)
            .append("'");

        return context;
    }

    @Override
    public Context addTableField(Context context, String schema, String tableName,
                                 List<AddTableFieldParam> paramList) {
        if (CollectionUtils.isEmpty(paramList)) {
            return context;
        }

        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        for (AddTableFieldParam addTableFieldParam : paramList) {
            context
                .appendWithSeparator("ALTER table")
                .appendWithSeparator(tableName)
                .appendWithSeparator("ADD COLUMN")
                .appendWithEscape(addTableFieldParam.getFieldName())
                .appendWithSeparator(addTableFieldParam.getFieldType())
                .appendWithSeparator(addTableFieldParam.isNullable() ? "DEFAULT null" : "not null")
                .append(";\n");
            if (StringUtils.isNotBlank(addTableFieldParam.getComment())) {
                context
                    .appendWithSeparator("COMMENT ON COLUMN")
                    .append(tableName)
                    .append(".")
                    .appendWithEscape(addTableFieldParam.getFieldName())
                    .appendWithSeparator("")
                    .appendWithSeparator("is")
                    .append("'")
                    .append(addTableFieldParam.getComment())
                    .append("'")
                    .appendNewSql();
            }
        }

        return context;
    }

    @Override
    public Context editTableField(Context context, String schema, String tableName,
                                  List<EditTableFieldParam> paramList) {
        if (CollectionUtils.isEmpty(paramList)) {
            return context;
        }

        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        for (EditTableFieldParam editTableFieldParam : paramList) {
            if (!StringUtils.equals(
                editTableFieldParam.getFieldName(), editTableFieldParam.getNewFieldName())
                && StringUtils.isNoneBlank(editTableFieldParam.getNewFieldName())) {
                context
                    .appendWithSeparator("ALTER TABLE ")
                    .appendWithSeparator(tableName)
                    .appendWithSeparator(" RENAME ")
                    .appendWithEscape(editTableFieldParam.getFieldName())
                    .appendWithSeparator(" to ")
                    .appendWithEscape(editTableFieldParam.getNewFieldName())
                    .appendNewSql();
            }
            String fieldName = Objects.requireNonNullElse(editTableFieldParam.getNewFieldName(), editTableFieldParam.getFieldName());
            // 修改类型 和 是否可空
            context
                .appendWithSeparator("alter table")
                .appendWithSeparator(tableName)
                .appendWithSeparator("alter COLUMN")
                .appendWithEscape(fieldName)
                .appendWithSeparator(" type")
                .appendWithSeparator(editTableFieldParam.getFieldType())
                .appendWithSeparator("USING")
                .appendWithEscape(fieldName)
                .append("::" + editTableFieldParam.getFieldType())
                .append(",")
                .appendWithSeparator("alter COLUMN")
                .appendWithEscape(fieldName)
                .appendWithSeparator(
                    editTableFieldParam.getNullable() != null && editTableFieldParam.getNullable()
                        ? "DROP NOT NULL" : " SET NOT NULL")
                .appendNewSql();
            context
                .appendWithSeparator("COMMENT ON COLUMN")
                .append(tableName)
                .append(".")
                .appendWithEscape(fieldName)
                .appendWithSeparator("")
                .appendWithSeparator("is")
                .append("'")
                .append(StringUtils.defaultString(editTableFieldParam.getComment()))
                .append("'")
                .appendNewSql();
        }
        return context;
    }

    @Override
    public Context deleteTableField(Context context, String schema, String tableName,
                                    List<String> fieldList) {
        if (CollectionUtils.isEmpty(fieldList)) {
            return context;
        }
        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        for (String field : fieldList) {
            context
                .appendWithSeparator("alter table")
                .appendWithSeparator(tableName)
                .appendWithSeparator("drop column if exists")
                .appendWithEscape(field)
                .appendNewSql();
        }
        return context;
    }

    @Override
    public Context getTableField(Context context, String schema, String tableName) {
        return null;
    }
}

class DMDDLer implements DDLer {

    @Override
    public Context create(Context context, CreateTableParam param) {
        String tableName =
            normalizedTableName(context.getEscape(), param.getDbName(), param.getTableName());
        final List<FieldInfo> primaryFields =
            param.getFieldInfoList().stream()
                .filter(FieldInfo::isPrimaryKey)
                .collect(Collectors.toList());

        List<String> keyFieldList = primaryFields.stream().map(e -> e.getFieldName())
            .collect(Collectors.toList());
        context.appendWithSeparator("CREATE TABLE ");

        context.appendWithSeparator(tableName);

        context.appendWithSeparator("(");

        for (CreateTableParam.FieldInfo fieldInfo : param.getFieldInfoList()) {
            context.appendWithEscape(fieldInfo.getFieldName()).append(" ");

            if (fieldInfo.isAutoIncrement()) {
                context.appendWithSeparator(" BIGINT IDENTITY(1, 1) NOT NULL");
            } else {
                context.appendWithSeparator(fieldInfo.getFieldType());
            }

            if (!fieldInfo.isNullable()) {
                context.appendWithSeparator("NOT NULL");
            }

            if (StringUtils.isNotBlank(fieldInfo.getDefaultVal())) {
                context.appendWithSeparator("DEFAULT").appendWithSeparator(fieldInfo.getDefaultVal());
            }

            if (keyFieldList.contains(fieldInfo.getFieldName())) {
                context.appendWithSeparator(" PRIMARY KEY ");
            }
            context.append(",");
        }
        context.deleteCharAt(context.getCurrentSql().length() - 1);

        context.appendWithSeparator(")").appendNewSql();

        if (StringUtils.isNotBlank(param.getTableComment())) {
            context.appendWithSeparator("COMMENT ON TABLE ");
            context.appendWithSeparator(tableName);
            context.append(" IS '").append(param.getTableComment()).append("'").appendNewSql();
        }

        final List<CreateTableParam.FieldInfo> hasCommentFields =
            param.getFieldInfoList().stream()
                .filter(f -> StringUtils.isNotBlank(f.getComment()))
                .collect(Collectors.toList());
        hasCommentFields.forEach(
            f -> {
                context.appendWithSeparator("COMMENT ON COLUMN ");
                context.append(tableName).append(Context.CONNECTOR).appendWithEscape(f.getFieldName());
                context.append(" IS '").append(f.getComment()).append("'").appendNewSql();
            });

        return context;
    }

    @Override
    public Context alterTableComment(Context context, String schema, String tableName,
                                     String comment) {
        tableName = normalizedTableName(context.getEscape(), schema, tableName);
        context
            .appendWithSeparator("comment on table")
            .appendWithSeparator(tableName)
            .appendWithSeparator("is")
            .append("'")
            .append(comment)
            .append("'");
        return context;
    }

    @Override
    public Context alterViewComment(Context context, String schema, String tableName,
                                    String comment) {
        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        context
            .appendWithSeparator("comment on view")
            .appendWithSeparator(tableName)
            .appendWithSeparator("is")
            .append("'")
            .append(comment)
            .append("'");

        return context;
    }

    @Override
    public Context addTableField(Context context, String schema, String tableName,
                                 List<AddTableFieldParam> paramList) {
        if (CollectionUtils.isEmpty(paramList)) {
            return context;
        }

        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        for (AddTableFieldParam addTableFieldParam : paramList) {
            context
                .appendWithSeparator("ALTER table")
                .appendWithSeparator(tableName)
                .appendWithSeparator("ADD COLUMN")
                .appendWithEscape(addTableFieldParam.getFieldName())
                .appendWithSeparator(addTableFieldParam.getFieldType())
                .appendWithSeparator(addTableFieldParam.isNullable() ? "DEFAULT NULL" : "NOT NULL")
                .append(";\n");
            if (StringUtils.isNotBlank(addTableFieldParam.getComment())) {
                context
                    .appendWithSeparator("COMMENT ON COLUMN")
                    .append(tableName)
                    .append(".")
                    .appendWithEscape(addTableFieldParam.getFieldName())
                    .appendWithSeparator("")
                    .appendWithSeparator("is")
                    .append("'")
                    .append(addTableFieldParam.getComment())
                    .append("'")
                    .appendNewSql();
            }
        }

        return context;
    }

    @Override
    public Context editTableField(Context context, String schema, String tableName,
                                  List<EditTableFieldParam> paramList) {
        if (CollectionUtils.isEmpty(paramList)) {
            return context;
        }

        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        for (EditTableFieldParam editTableFieldParam : paramList) {
            if (!StringUtils.equals(
                editTableFieldParam.getFieldName(), editTableFieldParam.getNewFieldName())
                && StringUtils.isNoneBlank(editTableFieldParam.getNewFieldName())) {
                context
                    .appendWithSeparator("ALTER TABLE ")
                    .appendWithSeparator(tableName)
                    .appendWithSeparator(" RENAME ")
                    .appendWithEscape(editTableFieldParam.getFieldName())
                    .appendWithSeparator(" to ")
                    .appendWithEscape(editTableFieldParam.getNewFieldName())
                    .appendNewSql();
            }
            String fieldName = Objects.requireNonNullElse(editTableFieldParam.getNewFieldName(), editTableFieldParam.getFieldName());
            // 修改类型 和 是否可空
            if (Objects.nonNull(editTableFieldParam.getNullable()) && editTableFieldParam.getNullable()) {
                context = context
                    .appendWithSeparator("alter table")
                    .appendWithSeparator(tableName)
//          .appendWithSeparator("alter COLUMN")
//          .appendWithEscape(fieldName)
//          .appendWithSeparator(" type")
//          .appendWithSeparator(editTableFieldParam.getFieldType())
//          .appendWithSeparator("USING")
//          .appendWithEscape(fieldName)
//          .append("::" + editTableFieldParam.getFieldType())
//          .append(",")
                    .appendWithSeparator("alter COLUMN ")
                    .appendWithEscape(fieldName)
                    .append("  SET NOT NULL;");
            }

            context
                .appendWithSeparator("COMMENT ON COLUMN")
                .append(tableName)
                .append(".")
                .appendWithEscape(fieldName)
                .appendWithSeparator("")
                .appendWithSeparator("is")
                .append("'")
                .append(StringUtils.defaultString(editTableFieldParam.getComment()))
                .append("'")
                .appendNewSql();
        }
        return context;
    }

    @Override
    public Context deleteTableField(Context context, String schema, String tableName,
                                    List<String> fieldList) {
        if (CollectionUtils.isEmpty(fieldList)) {
            return context;
        }
        tableName = normalizedTableName(context.getEscape(), schema, tableName);

        for (String field : fieldList) {
            context
                .appendWithSeparator("alter table")
                .appendWithSeparator(tableName)
                .appendWithSeparator("drop column if exists")
                .appendWithEscape(field)
                .appendNewSql();
        }
        return context;
    }

    @Override
    public Context getTableField(Context context, String schema, String tableName) {
        return null;
    }
}

class DDLFactory {

    static DDLer ddler(Database database) {
        switch (database) {
            case SAP:
                return new SAPSqlDDLer();
            case POSTGRESQL:
                return new PostgresSqlDDLer();
            case TIDB:
                return new TidbSqlDDLer();
            case HIVE:
                return new HiveDDLer();
            case DM:
                return new DMDDLer();
            case KINGBASE8:
                return new Kingbase8DDLer();
            default:
                throw new UnsupportedOperationException("暂不支持的数据库类型");
        }
    }
}
